using System;
using System.Collections;
using Castle.ActiveRecord;
using Castle.MonoRail.TestSupport;
using NUnit.Framework;
using NHibernate;
using Rhino.Mocks;
using Rhino.Mocks.Constraints;
using DecisionesInteligentes.iEvalua.Models;
using DecisionesInteligentes.iEvalua.Web.Controllers;
using DecisionesInteligentes.iEvalua.Tests.Helpers;

namespace DecisionesInteligentes.iEvalua.Tests.Controllers
{
	public class ControllerARMockTestCase<T, R> : BaseControllerTest where R:ActiveRecordBase<R> 
	{ 
		protected MockRepository mocks;
		protected ISession session;
		protected T controller = default(T);
		
		[TestFixtureSetUp]
		public virtual void TestFixtureSetUp()
		{
			Boot.Initialize();
		}
		
		[SetUp]
		public virtual void SetUp()
		{
			mocks = new MockRepository();
			session = mocks.CreateMock<ISession>();
		}

		[TearDown]
		public virtual void TearDown()
		{
			if(mocks != null)
				mocks.VerifyAll();
		}
		
		protected void DoApplicationSetup()
		{
			PreSetupApplication();
			SetupApplication();
			PostSetupApplication();
		}
		
		protected void PreSetupApplication()
		{
			mocks = new MockRepository();
			session = mocks.CreateMock<ISession>();
				
			IList apps = new ArrayList {
				new Application { 
					Id = 1, 
					Name = "iEvalua" }
			};
			
			ICriteria criteria = mocks.CreateMock<ICriteria>();

			using(mocks.Unordered())
			{
				Expect.Call(session.CreateCriteria(typeof(Application))).Return(criteria);
				Expect.Call(criteria.Add(null)).Constraints(
					Property.Value("Value", "iEvalua") & Property.Value("PropertyName", "Name")
				).Return(criteria);
				Expect.Call(criteria.SetFirstResult(0)).Return(criteria);
				Expect.Call(criteria.SetMaxResults(2)).Return(criteria);
				Expect.Call(criteria.List()).Return(apps);
			}
			
			mocks.ReplayAll();
		}
		
		protected void PostSetupApplication()
		{
			mocks.VerifyAll();
			
			mocks = new MockRepository();
			session = mocks.CreateMock<ISession>();
		}
		
		protected virtual void SetupApplication()
		{
		}
		
		protected virtual void List_SUT()
		{
		}
		
		protected void ShowList(R record)
		{
			IList list = new ArrayList {
				record
			};
			
			ICriteria criteria = mocks.CreateMock<ICriteria>();

			using(mocks.Unordered())
			{
				Expect.Call(session.CreateCriteria(typeof(R))).Return(criteria);
				Expect.Call(criteria.Add(null)).Constraints(
					Property.Value("Value", 1) & Property.Value("PropertyName", "ApplicationId")
				).Return(criteria);
				Expect.Call(criteria.List()).Return(list);
			}
			
			mocks.ReplayAll();
			
			using(new MockScope(session))
			{
				List_SUT();
			}
		}
		
		protected virtual void Create_SUT()
		{
		}
		
		protected void Create()
		{
			using(mocks.Unordered())
			{
				Expect.Call(session.Save(null)).IgnoreArguments().Return(null);
			}
			
			mocks.ReplayAll();

			using(new MockScope(session))
			{
				Create_SUT();
			}
		}
		
		protected virtual void Create_Invalid_SUT()
		{
		}
		
		protected void CreateInvalid()
		{
			mocks = null;
			
			Create_Invalid_SUT();
		}
		
		protected virtual void Create_Fail_SUT()
		{
		}
		
		protected void CreateFail()
		{
			using(mocks.Unordered())
			{
				Expect.Call(session.Save(null))
					.IgnoreArguments()
					.Throw(new Exception("Failed to save this record."));
			}
			
			mocks.ReplayAll();

			using(new MockScope(session))
			{
				Create_Fail_SUT();
			}
		}
		
		protected virtual void View_Edit_Existing_SUT()
		{
		}
		
		protected void ViewEditExisting(R record)
		{
			using(mocks.Unordered())
			{
				Expect.Call(session.Load(typeof(R), 1)).Return(record);
			}
			
			mocks.ReplayAll();
			
			using(new MockScope(session))
			{
				View_Edit_Existing_SUT();
			}
		}
		
		protected virtual void View_Edit_NonExisting_SUT()
		{
		}
		
		protected void ViewEditNonExisting(R record)
		{
			using(mocks.Unordered())
			{
				Expect.Call(session.Load(typeof(R), 0)).Return(null);
			}
			
			mocks.ReplayAll();
			
			using(new MockScope(session))
			{
				View_Edit_NonExisting_SUT();
			}
		}
		
		protected virtual void View_Edit_Load_Fail_Exception_SUT()
		{
		}
		
		protected void ViewEditLoadFailException(R record)
		{
			using(mocks.Unordered())
			{
				Expect.Call(session.Load(typeof(R), 1))
					.IgnoreArguments()
					.Throw(new Exception("Unknown exception"));
			}
			
			mocks.ReplayAll();
			
			using(new MockScope(session))
			{
				View_Edit_Load_Fail_Exception_SUT();
			}
		}
		
		protected virtual void Save_Existing_SUT()
		{
		}
		
		protected void SaveExisting(R record)
		{
			session.Update(null);
			LastCall.IgnoreArguments();
		
			mocks.ReplayAll();
		
			using(new MockScope(session))
			{
				Save_Existing_SUT();
			}
		}
		
		protected virtual void Save_Invalid_SUT()
		{
		}
		
		protected void SaveInvalid()
		{
			mocks = null;
			
			Save_Invalid_SUT();
		}
		
		protected virtual void Save_Exception_SUT()
		{
		}
		
		protected void SaveException()
		{
			using(mocks.Unordered())
			{
				session.Update(null);
				LastCall.IgnoreArguments()
					.Throw(new Exception("Unknown exception"));
			}
			
			mocks.ReplayAll();
			
			using(new MockScope(session))
			{
				Save_Exception_SUT();
			}
		}
	}
}